package mithrilwings.game;

import com.jme3.app.SimpleApplication;
import com.jme3.network.Filter;
import com.jme3.network.Filters;
import com.jme3.network.HostedConnection;
import com.jme3.network.Message;
import com.jme3.network.MessageListener;
import com.jme3.network.Network;
import com.jme3.network.Server;
import com.jme3.network.serializing.Serializer;
import com.jme3.system.JmeContext;
import java.io.IOException;
import java.util.Collection;
import java.util.StringTokenizer;
import mithrilwings.constants.Constants;
import mithrilwings.constants.MithrilMessage;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

/**
 *
 * @author porfiriopartida
 */
public class MithrilWingsSpiderServer extends SimpleApplication {

    final static protected Logger log4j = Logger.getLogger(MithrilWingsSpiderServer.class);
    static final long serialVersionUID = 1L;
    private Server myServer;

    public static void main(String[] args) {
        java.util.logging.Logger.getLogger("").setLevel(java.util.logging.Level.WARNING); // turning off jme log
        PropertyConfigurator.configure(Constants.LOG4J_PROPERTIES);
        try {
            MithrilWingsSpiderServer app = new MithrilWingsSpiderServer();
            app.start(JmeContext.Type.Headless); // headless type for servers!
            log4j.debug("Starting Headless server");
        } catch (Exception e) {
            log4j.fatal("Server Crashed", e);
        }
    }

    @Override
    public void simpleInitApp() {
        Serializer.registerClass(MithrilMessage.class);
        try {
            myServer = Network.createServer(Constants.PORT);
            myServer.start();
            log4j.debug("Listening on port " + Constants.PORT);
            myServer.addMessageListener(new ServerListener(), MithrilMessage.class);
        } catch (IOException ex) {
            log4j.error("Error initing server on port " + Constants.PORT, ex);
        }
    }

    class ServerListener implements MessageListener<HostedConnection> {

        static final long serialVersionUID = 1L;

        @Override
        public void messageReceived(HostedConnection client, Message message) {
//            log4j.debug("Message received " + message.toString());
            if (message instanceof MithrilMessage) {
                messageReceived(client, ((MithrilMessage) message).getMessage());
            }
        }

        public void messageReceived(HostedConnection client, String msg) {
            try {
//                String msg = message.getMessage();
                StringTokenizer tokenizer = new StringTokenizer(msg);
                int firstArg = Integer.parseInt(tokenizer.nextToken());
                switch (firstArg) {
                    case Constants.UPDATE_LOCATION_ROTATION:
//                    serverReporter.serverReport("UPDATE_LOCATION_ROTATION");
                        msg += " " + client.getId();
                        myServer.broadcast(Filters.notIn(client), new MithrilMessage(msg));
                        break;
                    case Constants.REQUEST_USERS:
                        log4j.debug("REQUEST_USERS");
                        Collection<HostedConnection> clientsList = myServer.getConnections();
                        for (final HostedConnection hc : clientsList) {
                            msg = Constants.ADD_USER + " " + hc.getId() + " ship_" + hc.getId();
                            myServer.broadcast(Filters.in(client), new MithrilMessage(msg));
                        }
                        break;
                    case Constants.REQUEST_ME:
                        log4j.debug("Requested me");
                        msg = Constants.REQUEST_ME + " " + client.getId();
                        myServer.broadcast(Filters.in(client), new MithrilMessage(msg));
                        break;

                    case Constants.ADD_USER:
                        log4j.debug("ADD_USER " + client.getAddress());
//                    serverReporter.serverReport("ADD_USER");
//                    ClientHandle newClient = clients.get(id);
//                    broadCast(Constants.ADD_USER + " " + newClient.getClientId()+ " " + newClient.getNickname(), id);
                        msg = Constants.ADD_USER + " " + client.getId() + " ship_" + client.getId();
                        myServer.broadcast(Filters.notIn(client), new MithrilMessage(msg));
                        break;

                    default:
                        msg += " " + client.getId();
                        log4j.warn("Mensaje desconocido : " + msg);
                        break;
                }
            } catch (Exception e) {
                String report = "Handle error";
                report += "\n";
                report += e.getMessage();
                report += "\n";
                report += client.getId() + " - " + msg;
//            serverReporter.serverReportError(report);
            }
        }
    }

    class MeFilter implements Filter {

        int myId;

        public MeFilter(int id) {
            this.myId = id;
        }

        @Override
        public boolean apply(Object input) {
            HostedConnection c = (HostedConnection) input;
            return c.getId() != myId;
        }
    };

    class NotMeFilter implements Filter {

        int myId;

        public NotMeFilter(int id) {
            this.myId = id;
        }

        @Override
        public boolean apply(Object input) {
            HostedConnection c = (HostedConnection) input;
            return c.getId() == myId;
        }
    };
}
